#include "MapCompile.h"
#include "Editor.h"
#include "BSPCompile.h"
#include "Basic/FileSystem.h"
#include "LibGL/GxUI.h"
#include "UIForm.h"
#include "Windows/GxThreads.h"

#define FM_COMPILE_NOTE WM_APP+10
#define FM_COMPILE_DONE WM_APP+11

namespace FinalRendering
{
	namespace Editor
	{
		using namespace GxLibBasic;
		using namespace GxWinSystem::Threading;

		struct CompileOptions
		{
			bool ComputeVisibility;
			int PvsMinSamples;
			float PvsGridSize;
		};

		class CompileDialog : public UIForm
		{
		private:
			CompileOptions options;
			GxRendering::UI::Button * btnCancel;
			GxRendering::UI::Label * lblStatus1, * lblStatus2;
			GxRendering::UI::ProgressBar * progBar;
			RefPtr<gxThread> thread;
			gxLock statLock;
			int progMax, progPos;
			String status1, status2;
		public:
			CompileDialog(CompileOptions & op)
			{
				SetClientWidth(300);
				SetClientHeight(86);
				SetTopMost(true);
				SetText(L"Compiling...");
				SetLeft(WorldEditor->GetMainForm()->GetLeft() + 
					(WorldEditor->GetMainForm()->GetWidth()-GetWidth())/2);
				SetTop(WorldEditor->GetMainForm()->GetTop() + 
					(WorldEditor->GetMainForm()->GetHeight()-GetHeight())/2);
				SetBorder(GxWinGUI::fbSingle);
				SetMaximizeBox(false);
				SetMinimizeBox(false);
				lblStatus1 = new Label();
				status1 = L"Initializing...";
				lblStatus1->SetText(status1);
				lblStatus1->Posit(10,10,280,20);
				lblStatus1->AutoSize = false;
				ui->AddChild(lblStatus1);

				lblStatus2 = new Label();
				lblStatus2->Posit(10,30,280,20);
				lblStatus2->AutoSize = false;
				ui->AddChild(lblStatus2);

				progBar = new GxRendering::UI::ProgressBar();
				progBar->Posit(10, 54, 210, 20);
				ui->AddChild(progBar);

				btnCancel = new GxRendering::UI::Button();
				btnCancel->SetText(L"Cancel");
				btnCancel->Posit(230, 50, 60, 26);
				btnCancel->OnClick.Bind(this, &CompileDialog::btnCancelClicked);
				ui->AddChild(btnCancel);

				OnClose.Bind(this, &CompileDialog::DoClose);

				compiling = false;
				cancelling = false;

				gxThreadProc * proc = new gxThreadProc();
				proc->Bind(this,  &CompileDialog::CompileThread);

				options = op;

				thread = new gxThread(proc);
				thread->Start();

			}

			void DoClose(Object * sender, GxWinGUI::WindowCloseEventArgs & e)
			{
				cancelling = true;
				e.Cancel = compiling;
			}

			bool ProcessMessage(GxWinGUI::WinMessage msg)
			{
				bool rs = UIForm::ProcessMessage(msg);
				if (msg.message == FM_COMPILE_DONE)
				{
					if (cancelling)
						MessageBeep(MB_ICONERROR);
					else
						MessageBeep(MB_ICONINFORMATION);
					Close();
				}
				else if (msg.message == FM_COMPILE_NOTE )
				{
					statLock.Lock();
					lblStatus1->SetText(status1);
					lblStatus2->SetText(status2);
					progBar->SetMax(progMax);
					progBar->SetPosition(progPos);
					statLock.Unlock();
				}
				return rs;
			}

			bool compiling;
			bool cancelling;

			void btnCancelClicked(UI_Base * sender)
			{
				cancelling = true;
			}

			void CompileThread()
			{
				compiling = true;
				RefPtr<Editor::Scene> scene = new Editor::Scene();
				scene->LoadFromFile(WorldEditor->Scene->FileName);
				BSP_Compiler compiler(scene.operator ->());
				compiler.PvsSamplingGrid = options.PvsGridSize;
				compiler.MinSamples = options.PvsMinSamples;
				compiler.ComputePVS = options.ComputeVisibility;
				compiler.OnProgressChanged.Bind(this, &CompileDialog::ProgressChanged);
				compiler.OnStatusChanged.Bind(this, &CompileDialog::StatusChanged);
				compiler.OnCheckCancel.Bind(this, &CompileDialog::CompilerCheckCancel);
				compiler.Compile(ExtractFileNameWithoutEXT(WorldEditor->Scene->FileName) + L".gxbsp");
				compiling = false;
				SendMessage(handle, FM_COMPILE_DONE, 0,0);
			}

			void CompilerCheckCancel(bool & cancel)
			{
				cancel = cancelling;
			}

			void ProgressChanged(int pos, int max)
			{
				statLock.Lock();
				progPos = pos;
				progMax = max;
				statLock.Unlock();
				SendMessage(handle, FM_COMPILE_NOTE, 0,0);
			}

			void StatusChanged(String stat1, String stat2)
			{
				statLock.Lock();
				status1 = stat1;
				status2 = stat2;
				statLock.Unlock();
				SendMessage(handle, FM_COMPILE_NOTE, 0,0);
			}
		};

		class CompileOptionsDialog : public UIForm
		{
		public:
			GxRendering::UI::TextBox * txtPvsGrid, * txtPvsMinSamples;
			GxRendering::UI::CheckBox * chkComputePVS;
			GxRendering::UI::Button * btnOK, * btnCancel;
		public:
			CompileOptionsDialog()
			{
				SetClientWidth(210);
				SetClientHeight(120);
				SetTopMost(true);
				SetText(L"Compiling Options");
				SetLeft(WorldEditor->GetMainForm()->GetLeft() + 
					(WorldEditor->GetMainForm()->GetWidth()-GetWidth())/2);
				SetTop(WorldEditor->GetMainForm()->GetTop() + 
					(WorldEditor->GetMainForm()->GetHeight()-GetHeight())/2);
				SetBorder(GxWinGUI::fbSingle);
				SetMaximizeBox(false);
				SetMinimizeBox(false);
				chkComputePVS = new GxRendering::UI::CheckBox();
				chkComputePVS->SetText(L"Compute Visibility");
				chkComputePVS->Posit(10,10, 200,18);
				chkComputePVS->Checked = true;
				chkComputePVS->BackColor.A = 0;
				ui->AddChild(chkComputePVS);
				Label * lbl;
				lbl = new GxRendering::UI::Label();
				lbl->SetText(L"PVS Cellspace:");
				lbl->Posit(10,32,80,20);
				ui->AddChild(lbl);
				txtPvsGrid = new GxRendering::UI::TextBox();
				txtPvsGrid->Posit(120,30,60,20);
				ui->AddChild(txtPvsGrid);
				lbl = new GxRendering::UI::Label();
				lbl->SetText(L"PVS Min. Samples:");
				lbl->Posit(10,57,60,20);
				ui->AddChild(lbl);
				txtPvsMinSamples = new GxRendering::UI::TextBox();
				txtPvsMinSamples->Posit(120,55,60,20);
				ui->AddChild(txtPvsMinSamples);
				GxRendering::UI::UpDown * ud;
				ud = new GxRendering::UI::UpDown(txtPvsGrid, 1.0f, 50.0f, 1.0f, 5.0f);
				ud->Digits = 1;
				ui->AddChild(ud);
				ud = new GxRendering::UI::UpDown(txtPvsMinSamples, 1.0f, 100.0f, 1.0f, 5.0f);
				ud->Digits = 0;
				ui->AddChild(ud);

				btnOK = new GxRendering::UI::Button();
				btnOK->Posit(70, 84, 60, 24);
				btnOK->SetText(L"OK");
				btnOK->OnClick.Bind(this, &CompileOptionsDialog::btnOKClicked);
				ui->AddChild(btnOK);

				btnCancel = new GxRendering::UI::Button();
				btnCancel->Posit(140, 84, 60, 24);
				btnCancel->SetText(L"Cancel");
				btnCancel->OnClick.Bind(this, &CompileOptionsDialog::btnCancelClicked);
				ui->AddChild(btnCancel);

				txtPvsGrid->SetText(L"32.0");
				txtPvsMinSamples->SetText(L"16");
			}
		private:
			void btnOKClicked(UI_Base * sender)
			{
				SetDialogResult(GxWinGUI::BaseForm::OK);
			}

			void btnCancelClicked(UI_Base * sender)
			{
				SetDialogResult(GxWinGUI::BaseForm::Cancel);
			}
		};

		bool CompileMap()
		{
			if (!WorldEditor->Save())
			{
				return false;
			}
			RefPtr<CompileOptionsDialog> dlgOp = new CompileOptionsDialog();
			
			if (dlgOp->ShowModal(WorldEditor->GetMainForm()) == GxWinGUI::BaseForm::OK)
			{
				CompileOptions op;
				op.ComputeVisibility = dlgOp->chkComputePVS->Checked;
				op.PvsGridSize = dlgOp->txtPvsMinSamples->GetText().ToFloat();
				op.PvsMinSamples = (int)dlgOp->txtPvsMinSamples->GetText().ToFloat();
				WorldEditor->dlgCompile = new CompileDialog(op);
				WorldEditor->dlgCompile->Show();
			}
			return true;
		}
	}
}